<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" /> 
    <title>条件变量与锁 - 天地维杰网</title>
    <meta name="keywords" content="系统架构,shutdown,不与天斗,Domino,博客,程序员,架构师,笔记,技术,分享,java,Redis">
    
    <meta property="og:title" content="条件变量与锁">
    <meta property="og:site_name" content="天地维杰网">
    <meta property="og:image" content="/img/author.jpg"> 
    <meta name="title" content="条件变量与锁 - 天地维杰网" />
    <meta name="description" content="本文以linux c为例子, 介绍锁和共享变量的基本使用方法, 并介绍一个基于条件变量实现生产者消费者模型的例子, 然后在文末给出相关书籍的参考." />
     
    <link rel="shortcut icon" href="http://www.shutdown.cn/img/favicon.ico" />
    <link rel="apple-touch-icon" href="http://www.shutdown.cn/img/apple-touch-icon.png" />
    <link rel="apple-touch-icon-precomposed" href="http://www.shutdown.cn/img/apple-touch-icon.png" />
    <link href="http://www.shutdown.cn/js/vendor/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />
    <link href="http://www.shutdown.cn/js/vendor/fancybox/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />
    <link href="http://www.shutdown.cn/css/main.css" rel="stylesheet" type="text/css" />
    <link href="http://www.shutdown.cn/css/syntax.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript" id="hexo.configuration">
  var NexT = window.NexT || {};
  var CONFIG = {
    scheme: 'Pisces',
    sidebar: {"position":"left","display":"post"},
     fancybox: true, 
    motion: true
  };
</script>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-7826003325059020" crossorigin="anonymous"></script>
</head>
<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">
<div class="container one-collumn sidebar-position-left page-home  ">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"> <div class="site-meta  custom-logo ">

  <div class="custom-logo-site-title">
    <a href="http://www.shutdown.cn"  class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <span class="site-title">天地维杰网</span>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>
  <p class="site-subtitle">人如秋鸿来有信，事若春梦了无痕</p>
</div>

<div class="site-nav-toggle">
  <button>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
  </button>
</div>

<nav class="site-nav">
    <ul id="menu" class="menu">
      
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />首页
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/redis/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-battery-full"></i> <br />Redis
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/java/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-coffee"></i> <br />java
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/linux/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-linux"></i> <br />linux
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/daily/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-bug"></i> <br />日常问题
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/spring/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-child"></i> <br />Spring和Springboot
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/mac/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-fire"></i> <br />Mac相关
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/middleware/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-gavel"></i> <br />中间件
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/jiagou/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-rocket"></i> <br />架构
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/python/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-ship"></i> <br />python
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/front/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-bolt"></i> <br />前端
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/jvm/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-balance-scale"></i> <br />jvm
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/c/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-battery-empty"></i> <br />c语言
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/categories/web3/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-web3"></i> <br />web3
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/post/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />归档
          </a>
        </li>
      
        <li class="menu-item ">
          <a href="http://www.shutdown.cn/about/" rel="section">
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />关于
          </a>
        </li>
      
      <li class="menu-item menu-item-search">
        <a href="javascript:;" class="popup-trigger"> <i class="menu-item-icon fa fa-search fa-fw"></i> <br /> 搜索</a>
      </li>
    </ul>
    <div class="site-search">
      <div class="popup">
 <span class="search-icon fa fa-search"></span>
 <input type="text" id="local-search-input">
 <div id="local-search-result"></div>
 <span class="popup-btn-close">close</span>
</div>

    </div>
</nav>

 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            
<section id="posts" class="posts-expand">
  <article class="post post-type-normal " itemscope itemtype="http://schema.org/Article">
    <header class="post-header">
      <h1 class="post-title" itemprop="name headline">
        <a class="post-title-link" href="http://www.shutdown.cn/post/linux-c-condition-var-and-lock/" itemprop="url">
        条件变量与锁
        </a>
      </h1>
      <div class="post-meta">
      <span class="post-time">
<span class="post-meta-item-icon">
    <i class="fa fa-calendar-o"></i>
</span>
<span class="post-meta-item-text">时间：</span>
<time itemprop="dateCreated" datetime="2016-03-22T13:04:35+08:00" content="2022-10-24">
    2022-10-24
</time>
</span> 
      

  <span class="post-category" >
  &nbsp; | &nbsp;
  <span class="post-meta-item-icon">
    <i class="fa fa-folder-o"></i>
  </span>
  <span class="post-meta-item-text">分类：</span>
  
    <span itemprop="about" itemscope itemtype="https://schema.org/Thing">
      <a href="http://www.shutdown.cn/categories/linux" itemprop="url" rel="index">
        <span itemprop="name">linux</span>
      </a>
      &nbsp; 
    </span>
  
</span>


      
 <span>
&nbsp; | &nbsp;
<span class="post-meta-item-icon">
    <i class="fa fa-eye"></i>
</span>
<span class="post-meta-item-text">转载</span>
</span>

       <span>
&nbsp; | &nbsp;
<span class="post-meta-item-icon">
    <i class="fa fa-eye"></i>
</span>
<span class="post-meta-item-text">阅读：</span>
<span class="leancloud-visitors-count">2606 字 ~6分钟</span>
</span>
      </div>
    </header>
    <div class="post-body" itemprop="articleBody">
    
    <div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-fallback" data-lang="fallback"> 文章系转载，便于整理和分类，原文地址：https://yiwenshao.github.io/2016/11/05/%E6%9D%A1%E4%BB%B6%E5%8F%98%E9%87%8F%E4%B8%8E%E9%94%81/</code></pre></div>
    

    

<p>本文以linux c为例子, 介绍锁和共享变量的基本使用方法, 并介绍一个基于条件变量实现生产者消费者模型的例子, 然后在文末给出相关书籍的参考.</p>

<h3 id="锁">锁</h3>

<p>多线程情况下, 锁的使用主要涉及以下5个函数, 它们都包含在pthread.h头文件中.</p>

<ul>
<li>pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t *attr)</li>
<li>pthread_mutex_lock(pthread_mutex_t *mutex)</li>
<li>pthread_mutex_tylock(pthread_mutex_t *mutex)</li>
<li>pthread_mutex_unlock(pthread_mutex_t *mutex)</li>
<li>pthread_mutex_destroy(pthread_mutex_t *mutex)</li>
</ul>

<p>其中, 锁变量类型为pthread_mutex_t, 锁的使用包含三个步骤, 分别是锁的初始化, 加锁, 以及释放锁.</p>

<p>下面分别介绍各个函数的用法</p>

<h4 id="锁初始化">锁初始化</h4>

<p>pthread_mutex_init该函数用于锁的初始化, 其函数头是</p>

<p><strong>pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t *attr)</strong></p>

<p>要使用锁, 首先需要声明一个pthread_mutex_t变量,然后用该函数进行初始化, 如下</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#000">pthread_mutex_t</span> <span style="color:#000">mutex</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#000">pthread_mutex_init</span><span style="color:#000;font-weight:bold">(</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">mutex</span><span style="color:#000;font-weight:bold">,</span><span style="color:#204a87">NULL</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span></code></pre></div>
<p>初始化的时候, 第二个参数可以用于设置锁的性质, 设置方法可以参考文末的参考文献. 经过这一步, 我们完成了锁的初始化. 在第二个参数设置NULL的时候, 一个线程加锁, 另外一个线程再执行加锁操作, 就会阻塞, 直到另外的线程释放锁. 加锁可以用下面的函数来完成.</p>

<h4 id="加锁">加锁</h4>

<p>pthread_mutex_lock与pthread_mutex_tylock这两个函数可以用于加锁, 其函数头分别是:</p>

<p><strong>pthread_mutex_lock(pthread_mutex_t *mutex)</strong></p>

<p><strong>pthread_mutex_tylock(pthread_mutex_t *mutex)</strong></p>

<p>这两个函数都完成了加锁的功能, 在获得了变量初始化后的mutex以后, 直接调用函数即可完成加锁功能. 其中第一个函数在另外一个线程已经获得锁的情况下, 会一直阻塞, 而第二个函数则会直接返回, 不会阻塞.</p>

<h4 id="释放锁">释放锁</h4>

<p><strong>pthread_mutex_unlock(pthread_mutex_t *mutex)</strong>函数可以用于释放锁.</p>

<h4 id="回收资源">回收资源</h4>

<p><strong>pthread_mutex_destroy(pthread_mutex_t *mutex)</strong>该函数用于释放资源, 在使用pthread_mutex_init函数进行锁初始化的情况下, 使用结束以后,需要使用该函数释放资源.</p>

<h3 id="共享变量">共享变量</h3>

<p>共享变量应用于这样一种场景: 一个线程先对某一条件进行判断, 如果条件不满足则进入等待, 条件满足的时候, 该线程被通知条件满足, 继续执行任务. 共享变量涉及的函数有如下6个</p>

<ul>
<li>int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr)</li>
<li>int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)</li>
<li>int pthread_cond_signal(pthread_cond_t *cond)</li>
<li>int pthread_cond_broadcast(pthread_cond_t *cond)</li>
<li>int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)</li>
</ul>

<h4 id="初始化">初始化</h4>

<p><strong>int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr)</strong></p>

<p>要使用条件变量, 首先要声明一个pthread_cond_t变量, 然后用该函数进行初始化. 第二个参数使用NULL, 具体的参数设置, 限于篇幅, 参考文末的参考文献.</p>

<h4 id="等待条件成立">等待条件成立</h4>

<p><strong>int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)</strong></p>

<p><strong>int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)</strong></p>

<p>在条件不满足的时候, 调用该函数进入等待. 当条件满足的时候, 该函数会停止等待, 继续执行. 该函数的第二个参数是pthread_mutex_t类型, 这是因为在条件判断的时候, 需要先进行加锁来防止出现错误, 在执行改函数前需要主动对这个变量执行加锁操作, 进入这个函数以后, <strong>其内部会对mutex进行解锁操作</strong>, 而函数执行完以后(也就是停止阻塞以后), 又会重新加锁. 具体原因, 在介绍完本组函数以后进行说明. 其中第二个函数可以指定等待的时间, 而不是一直在阻塞.</p>

<h4 id="通知">通知</h4>

<p><strong>int pthread_cond_signal(pthread_cond_t *cond)</strong></p>

<p><strong>int pthread_cond_broadcast(pthread_cond_t *cond)</strong></p>

<p>上面说到, 在条件不满足的时候, 一个线程会调用pthread_cond_wait函数, 阻塞等待. 而此时如果其他线程检查到条件满足, 则可以调用这两个函数, 让处于等待状态的线程重新开始执行. 当有多个线程在等待的时候, 第一个函数会唤醒其中一个线程, 而第二个函数会唤醒所有的等待的线程.</p>

<h3 id="共享变量与锁">共享变量与锁</h3>

<p>介绍完了基本的函数功能, 接下来介绍这两套函数配合使用的一个常见场景: 有两个线程, 其中一个线程先对一个条件进行检查, 这个检查动作需要先加锁. 如果条件成立, 则执行操作, 否则阻塞等待, 直到条件成立, 这个线程才会被通知继续执行. 另一个线程先做加锁处理, 然后置条件为真, 并通知其他等待的线程条件已经满足, 可以继续执行.</p>

<p>上面说在检查共享变量的时候, 要加锁, 其原因通过以下伪代码来说明.</p>

<p>第一种情况</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#8f5902;font-style:italic">#</span><span style="color:#8f5902;font-style:italic">线程1</span><span style="color:#8f5902;font-style:italic">
</span><span style="color:#8f5902;font-style:italic"></span><span style="color:#000">pthread_mutex_lock</span><span style="color:#000;font-weight:bold">(</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">mutex</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span> 
<span style="color:#204a87;font-weight:bold">while</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">condition</span> <span style="color:#ce5c00;font-weight:bold">=</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">FALSE</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>
    <span style="color:#000">pthread_cond_wait</span><span style="color:#000;font-weight:bold">(</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">cond</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">mutex</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span> 
<span style="color:#000;font-weight:bold">}</span>
<span style="color:#000">pthread_mutex_unlock</span><span style="color:#000;font-weight:bold">(</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">mutex</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>

<span style="color:#8f5902;font-style:italic">#</span><span style="color:#8f5902;font-style:italic">线程2</span><span style="color:#8f5902;font-style:italic">
</span><span style="color:#8f5902;font-style:italic"></span><span style="color:#000">condition</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">TRUE</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#000">pthread_cond_signal</span><span style="color:#000;font-weight:bold">(</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">cond</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span></code></pre></div>
<p>可以看到, 线程1先检查一个条件是否成立, 在不成立的情况下, 就调用wait函数进行等待. 而在这之前, 先对这步过程进行了加锁操作. 线程2则是把条件设置为true(假设其通过某种方式知道了这个时候该条件应当为true), 然后用pthread_cond_signal函数通知线程1停止阻塞继续执行. 上面的程序在多个线程并发执行的时候有如下的问题:
如果线程1先判断, 发现条件不满足, 准备进入等待, 在这个时候, 线程2中条件被置为真, 且发送通知. 然后线程1才阻塞等待, 这样的话, 线程1错过了一次通知, 导致其在条件满足的情况下依然在阻塞等待.</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c">        <span style="color:#a40000">线</span><span style="color:#a40000">程</span><span style="color:#0000cf;font-weight:bold">1</span>                               <span style="color:#a40000">线</span><span style="color:#a40000">程</span><span style="color:#0000cf;font-weight:bold">2</span>
<span style="color:#000">pthread_mutex_lock</span><span style="color:#000;font-weight:bold">(</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">mutex</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#204a87;font-weight:bold">while</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">condition</span> <span style="color:#ce5c00;font-weight:bold">=</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">FALSE</span><span style="color:#000;font-weight:bold">)</span>
                                      <span style="color:#000">condition</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">TRUE</span><span style="color:#000;font-weight:bold">;</span>
                                      <span style="color:#000">pthread_cond_signal</span><span style="color:#000;font-weight:bold">(</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">cond</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#000">pthread_cond_wait</span><span style="color:#000;font-weight:bold">(</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">cond</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">mutex</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span></code></pre></div>
<p>为了解决上面说的问题, 对程序进行了如下的改进. 通过线程2的加锁操作, 避免了这样的问题. 这也解释了为什么pthread_cond_wait函数在进入以后要进行解锁操作, 如果起不解锁, 那么线程2在进行条件置为true的操作就没有办法执行, 因为线程1在进入等待之前已经对这个变量加锁了. 这样线程1会一直等待, 而线程2也会等待, 导致死锁.</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#a40000">线</span><span style="color:#a40000">程</span><span style="color:#0000cf;font-weight:bold">1</span>                                       <span style="color:#a40000">线</span><span style="color:#a40000">程</span><span style="color:#0000cf;font-weight:bold">2</span>
<span style="color:#000">pthread_mutex_lock</span><span style="color:#000;font-weight:bold">(</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">mutex</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>           <span style="color:#000">pthread_mutex_lock</span><span style="color:#000;font-weight:bold">(</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">mutex</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#204a87;font-weight:bold">while</span> <span style="color:#000;font-weight:bold">(</span><span style="color:#000">condition</span> <span style="color:#ce5c00;font-weight:bold">=</span><span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">FALSE</span><span style="color:#000;font-weight:bold">)</span> <span style="color:#000;font-weight:bold">{</span>          <span style="color:#000">condition</span> <span style="color:#ce5c00;font-weight:bold">=</span> <span style="color:#000">TRUE</span><span style="color:#000;font-weight:bold">;</span>
 <span style="color:#000">pthread_cond_wait</span><span style="color:#000;font-weight:bold">(</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">cond</span><span style="color:#000;font-weight:bold">,</span> <span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">mutex</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>    <span style="color:#000">pthread_cond_signal</span><span style="color:#000;font-weight:bold">(</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">cond</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#000;font-weight:bold">}</span>                                     <span style="color:#000">pthread_mutex_unlock</span><span style="color:#000;font-weight:bold">(</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">mutex</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span>
<span style="color:#000">pthread_mutex_unlock</span><span style="color:#000;font-weight:bold">(</span><span style="color:#ce5c00;font-weight:bold">&amp;</span><span style="color:#000">mutex</span><span style="color:#000;font-weight:bold">)</span><span style="color:#000;font-weight:bold">;</span></code></pre></div>
<p>补充说明一点,因为wait重新执行的时候需要再次加锁,所以上面的pthread_cond_signal调用以后, 必须释放锁,才能够完成wait. 另外, 也可以先解锁, 然后调用pthread_cond_signal,这两种写法都是正确的. 虽然共享变量的访问一般需要加锁, 但在这个场景下不加锁造成的竞争不会产生错误, 只是会造成线程调度效率上的问题, 所以也可以这么写, 但是一般推荐标准的写法. 具体可以看参考文献.</p>

<h3 id="条件变量的使用例子">条件变量的使用例子</h3>

<p>下面的链接以redis 3.2.3的代码中的BIO模块为例子, 给出实际系统中的条件变量使用的方法. 可以发现, redis的BIO模块就是用上面介绍的模型实现的.</p>

<p><a href="http://www.shutdown.cn/post/redis-bio-system/">Redis BIO系统</a></p>

<h3 id="总结">总结</h3>

<p>锁的基本使用包括了锁初始化, 加锁, 解锁三个步骤. 使用默认的锁性质时, 一个锁变量只能由一个线程获得, 在这个线程释放锁之前, 其他线程如果尝试获得锁, 就会进入阻塞的状态. 这样, 加锁和解锁之间的这段代码只有一个线程执行, 从而能够保证并发访问的正确性.</p>

<p>对于条件变量, 其基本的使用场景是, 某些线程对条件进行判断, 如果不满足条件, 就进入等待状态. 在进行条件判断之前, 先进行加锁操作. 另外一些线程则是负责对条件赋值为真, 然后通知等待的线程继续执行, 线程被唤醒后, 继续进入判断的环节以及后续的操作.</p>

<p>以上面例子来看, 也就是可以分为以下两部分:</p>

<p>A类线程:</p>

<ul>
<li>加锁</li>
<li>检查(条件不成立则等待,知道成立再次进入检查阶段)</li>
<li>执行</li>
<li>解锁</li>
</ul>

<p>B类线程:</p>

<ul>
<li>加锁</li>
<li>条件置为真</li>
<li>通知</li>
<li>解锁</li>
</ul>

<h3 id="参考文献">参考文献</h3>

<p><a href="https://yiwenshao.github.io/2016/11/05/条件变量与锁/">1.Unix Networking Programming, Volume 2, W. Richard Stevens, chapter 7, 8</a>
<a href="http://stackoverflow.com/questions/4544234/calling-pthread-cond-signal-without-locking-mutex">2.stackoverflow/questions/4544234/</a>
<a href="https://yiwenshao.github.io/2016/11/05/Redis的BIO系统/">3.Redis BIO系统</a>
<a href="http://stackoverflow.com/questions/6312342/pthread-cond-wait-and-mutex-requirement">4.http://stackoverflow.com/questions/6312342/</a></p>

    </div>
    <footer class="post-footer">
     
 
<div class="post-tags">     
     
    <a href="http://www.shutdown.cn/tags/linux" rel="tag" title="linux">#linux#</a>
    
    <a href="http://www.shutdown.cn/tags/c" rel="tag" title="c">#c#</a>
    
    <a href="http://www.shutdown.cn/tags/%e9%94%81" rel="tag" title="锁">#锁#</a>
    
    <a href="http://www.shutdown.cn/tags/pthread" rel="tag" title="pthread">#pthread#</a>
    
</div>



     <div class="post-nav">
    <div class="post-nav-next post-nav-item">
    
        <a href="http://www.shutdown.cn/post/redis-data-expire-evict-policy-detail/" rel="next" title="Redis数据过期和淘汰策略详解">
        <i class="fa fa-chevron-left"></i> Redis数据过期和淘汰策略详解
        </a>
    
    </div>

    <div class="post-nav-prev post-nav-item">
    
        <a href="http://www.shutdown.cn/post/redis-source-code-learn-of-bio/" rel="prev" title="Redis源码学习之BIO">
        Redis源码学习之BIO <i class="fa fa-chevron-right"></i>
        </a>
    
    </div>
</div>
      
     
     
     






    </footer>
  </article>
</section>

          </div>
        </div>
        <div class="sidebar-toggle">
  <div class="sidebar-toggle-line-wrap">
    <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
    <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
    <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
  </div>
</div>
<aside id="sidebar" class="sidebar">
  <div class="sidebar-inner">

  <ul class="sidebar-nav motion-element">
    <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap" >
      文章目录
    </li>
    <li class="sidebar-nav-overview" data-target="site-overview">
      站点概览
    </li>
  </ul>

    <section class="site-overview sidebar-panel ">
      <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image"
        src="http://www.shutdown.cn/img/author.jpg"
        alt="不与天斗Domino" />
    <p class="site-author-name" itemprop="name">不与天斗Domino</p>
    <p class="site-description motion-element" itemprop="description"> 
        Programmer &amp; Architect</p>
</div>
      <nav class="site-state motion-element">
    <div class="site-state-item site-state-posts">
      <a href="http://www.shutdown.cn/post/">
        <span class="site-state-item-count">183</span>
        <span class="site-state-item-name">日志</span>
      </a>
    </div>
    <div class="site-state-item site-state-categories">    
        <a href="http://www.shutdown.cn/categories/">      
         
        <span class="site-state-item-count">15</span>
        
        <span class="site-state-item-name">分类</span>
        
        </a>
    </div>

    <div class="site-state-item site-state-tags">
        <a href="http://www.shutdown.cn/tags/">
         
        <span class="site-state-item-count">224</span>
        
        <span class="site-state-item-name">标签</span>
        </a>
    </div>
</nav>
      
      

      

      <div class="links-of-blogroll motion-element inline">
<script type="text/javascript" src="//rf.revolvermaps.com/0/0/8.js?i=&amp;m=0&amp;s=220&amp;c=ff0000&amp;cr1=ffffff&amp;f=arial&amp;l=33&amp;bv=35" async="async"></script>
</div>

    </section>
    
<section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
    <div class="post-toc">
        <div class="post-toc-content"><nav id="TableOfContents">
<ul>
<li>
<ul>
<li>
<ul>
<li><a href="#锁">锁</a>
<ul>
<li><a href="#锁初始化">锁初始化</a></li>
<li><a href="#加锁">加锁</a></li>
<li><a href="#释放锁">释放锁</a></li>
<li><a href="#回收资源">回收资源</a></li>
</ul></li>
<li><a href="#共享变量">共享变量</a>
<ul>
<li><a href="#初始化">初始化</a></li>
<li><a href="#等待条件成立">等待条件成立</a></li>
<li><a href="#通知">通知</a></li>
</ul></li>
<li><a href="#共享变量与锁">共享变量与锁</a></li>
<li><a href="#条件变量的使用例子">条件变量的使用例子</a></li>
<li><a href="#总结">总结</a></li>
<li><a href="#参考文献">参考文献</a></li>
</ul></li>
</ul></li>
</ul>
</nav></div>
    </div>
</section>

  </div>
</aside>

      </div>
    </main>
   
    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  <span itemprop="copyrightYear">  &copy; 
  2013 - 2023</span>
  <span class="with-love"><i class="fa fa-heart"></i></span>
  <span class="author" itemprop="copyrightHolder">天地维杰网</span>
  <span class="icp" itemprop="copyrightHolder"><a href="https://beian.miit.gov.cn/" target="_blank">京ICP备13019191号-1</a></span>
</div>
<div class="powered-by">
  Powered by - <a class="theme-link" href="http://gohugo.io" target="_blank" title="hugo" >Hugo v0.63.2</a>
</div>
<div class="theme-info">
  Theme by - <a class="theme-link" href="https://github.com/xtfly/hugo-theme-next" target="_blank"> NexT
  </a>
</div>


      </div>
    </footer>

    <div class="back-to-top">
      <i class="fa fa-arrow-up"></i>
      <span id="scrollpercent"><span>0</span>%</span>
    </div>
  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/jquery/index.js?v=2.1.3"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/fastclick/lib/fastclick.min.js?v=1.0.6"></script> 
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/velocity/velocity.min.js?v=1.2.1"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/vendor/velocity/velocity.ui.min.js?v=1.2.1"></script>
<script src="http://www.shutdown.cn/js/vendor/ua-parser-js/dist/ua-parser.min.js?v=0.7.9"></script>

<script src="http://www.shutdown.cn/js/vendor/fancybox/jquery.fancybox.pack.js?v=2.1.5"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/utils.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/motion.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/affix.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/schemes/pisces.js"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/scrollspy.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/post-details.js"></script>
<script type="text/javascript" src="http://www.shutdown.cn/js/toc.js"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/bootstrap.js"></script>

<script type="text/javascript" src="http://www.shutdown.cn/js/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js"],
    jax: ["input/TeX", "output/HTML-CSS"],
    tex2jax: {
      inlineMath: [ ['$','$'] ],
      displayMath: [ ['$$','$$'] ],
      processEscapes: true
    },
    "HTML-CSS": { fonts: ["TeX"] }
  });
</script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML' async></script>
</body>
</html>